import { _decorator, Component, game, Label, Node, SpriteFrame, sys } from 'cc';
import { DEBUG } from 'cc/env';
import MutiLang from 'db://cocos-ext/base/MutiLang';
import ScrollProgressBar from 'db://cocos-ext/component/ScrollProgressBar';
import { games, lobby, players, rooms, yy } from 'yycore';

import YYExt from '../../yyExt/YYExt';

const { ccclass, property } = _decorator;

@ccclass('LoginScene')
export class LoginScene extends Component {

    @property(SpriteFrame)
    private readonly sfMask: SpriteFrame = null;

    // 用于调试的登录UI
    @property(Node)
    private readonly ndLogin: Node = null;

    // lodaing UI 
    @property(Node)
    private readonly ndLoading: Node = null;

    @property(Label)
    private readonly lbProgressStatus: Label = null;

    @property(ScrollProgressBar)
    private readonly barProgress: ScrollProgressBar = null;

    @property(Label)
    private readonly lbVersion: Label = null;

    private _update: games.IAutoUpdate = null;

    // 是否展示模拟登录
    private get isTestLogin(): boolean {
        return !!yy.env.cfg.isDebug && DEBUG;
    }

    onLoad() {
        yy.sys.setCurrentLanguage('en');

        this.ndLoading.active = true;
        this.ndLogin.active = this.isTestLogin;
        this.lbVersion.string = '';
        this.lbProgressStatus.string = 'Version checking ...';
        this.barProgress.node.active = false;

        // 移除黑色过渡
        // games.ui.manager.setSingleColorSpriteFrame(this.sfMask);

        // 给框架注册一些场景和纹理资源
        games.ui.manager.setSceneFire(games.ui.SceneType.Lobby, "LoginScene", null);
        games.ui.manager.setSceneFire(games.ui.SceneType.GameLoading, "GameSceneTemp", null);
        games.ui.manager.setSceneFire(games.ui.SceneType.RoomSelect, "GameRoomScene", null);

        // 监听解析配置完成事件
        yy.event.on(this, games.events.GameConfigReady, this._onGameConfigReady);
        // 监听版本检测完成事件
        yy.event.on(this, games.events.VersionCheckReady, this._onVersionCheckReady);
        // 监听登陆大厅结果事件
        yy.event.on(this, lobby.events.LoginLobbyResult, this._onLoginLobbyResult);
    }

    start() {
        DEBUG && console.log('# enter login ...');

        // 这里是为了注册下公共服务，使子游戏可以读取公共库下的服务
        rooms.service;
    }

    // config.json 加载完毕，这个时候系统已经知道了主游戏是什么
    private _onGameConfigReady(e: games.events.GameConfigReady) {
        DEBUG && console.debug('配置加载事件完成', e);

        //因为不同的主游戏，数据存储的路径不一样，因此读取这些数据的时候，必须先知道主游戏ID是啥
        //系统在需要等到config.json加载完毕才知道
        this.lbVersion.string = yy.env.cfg.appVer || '1.0.0.0';

        // 初始化音效设置(单款游戏默认开启音效)
        games.setting.isMute = false;
        games.setting.isMusicEnable = true;
        games.setting.isEffectEnable = true;
        games.setting.isVoiceEnable = true;
    }

    // 版本检测完成回调
    private _onVersionCheckReady(e: games.events.VersionCheckReady) {
        DEBUG && console.debug('版本检测事件完成', e);
        // 在浏览器运行时，e.lobbyHasNewVersion永远为false; 游戏内登录状态变化，不执行热更新
        if (e && e.lobbyHasNewVersion) {
            if (e.updateLobbyURL) {
                sys.openURL(e.updateLobbyURL);
            } else {
                this._update = games.updateMgr.updateToNewVersion();
                if (this._update) {
                    // 发现新版本，正在更新...

                    // 监听进度和结果事件
                    yy.event.on(this, games.events.UpdateEvent, (e) => {
                        if (e.autoUpdate == this._update) {
                            const Code = games.events.UpdateEventCode;
                            if (e.eventCode == Code.ReadUpdateInfo) {
                                this.barProgress.value = 0;
                                this.barProgress.node.active = true;
                                this.lbProgressStatus.string = 'New version found, please waiting ...';
                                // 判断是否弹框提示用户 
                                let ver = this._update.getDownloader().getRemoteManifest().getVersion();
                                let msg = `New version (${games.site.lobbyVersion}-${ver})\nPlease try to update. (` + Math.ceil(e.total / 1024) + 'KB)';
                                games.ui.messageBox(msg, (btn) => {
                                    if (btn === games.ui.MBBtn.Yes) {
                                        e.autoUpdate.update();
                                    } else {
                                        DEBUG && console.error('# Do not update and game end !!!');
                                        game.end();
                                    }
                                }, this, games.ui.MBBtnType.Yes, 'MB_Test');
                            } else if (e.eventCode == Code.Progress) {
                                // 进度事件
                                this.barProgress.scrollTo(0.1, e.progress);
                                this.lbProgressStatus.string = 'Downloading ... ' + (e.progress * 100 >> 0) + '%';
                            } else if (e.eventCode == Code.Succeed) {
                                this.barProgress.scrollTo(0.1, 1);
                                // 更新成功之后，如果更新的是APK,框架会自动启动安装
                                // 如果是普通的热更新，框架将自动重启APP，所以这里不需要做什么事情
                                DEBUG && console.warn('版本更新成功');
                                this.lbProgressStatus.string = 'Download finish ...';
                            } else if (e.eventCode == Code.Failed) {
                                if (e.autoUpdate.canRetry()) {
                                } else {
                                    // 更新失败，不可以重试
                                }
                            } else if (e.eventCode == Code.Finish) {
                                DEBUG && console.warn('检测更新完成');
                                this.lbProgressStatus.string = 'Checking finish ...';
                                this.ndLoading.active = false;
                                this.ndLogin.active = this.isTestLogin;
                            }
                        }
                    });
                    // 注意，当前下载更新的可能是APK，也可能是热更新，前端接口统一,不需要关心到底在更新什么。
                } else {
                    // 更新失败
                    DEBUG && console.error('大厅启动更新失败');
                }
            }
        }
        else {
            // 不需要更新
            DEBUG && console.warn('大厅不需要更新');

            let modules = yy.env.cfg.modules;
            if (modules && modules.length > 0) {
                let remoteUrl = games.site.getSer(1)?.host;
                let total = modules.length;
                let loaded = 0;
                this.barProgress.value = 0;
                this.barProgress.node.active = true;
                this.lbProgressStatus.string = `Load resources (${loaded >> 0}/${total})`;

                let onLoaded = () => {
                    if (loaded >= total) {
                        this.scheduleOnce(() => {
                            this.barProgress.node.active = false;
                            this.lbProgressStatus.string = `Logining ...`;
                            this._quickLogin();
                        }, 0.5);
                    }
                }

                for (let m of modules) {
                    if (m.bundle) {
                        games.bundleMgr.load(m.name, (DEBUG || m.local) ? null : remoteUrl, (err) => {
                            if (err)
                                return DEBUG && console.error(`load ${m.name}(${m.version}) bundle err:`, err);

                            loaded += 1;
                            this.barProgress.scrollTo(0.1, loaded / total);
                            this.lbProgressStatus.string = `Load resources (${loaded >> 0}/${total})`;
                            onLoaded();
                        });
                    }
                    else {
                        loaded += 1;
                        this.barProgress.scrollTo(0.1, loaded / total);
                        this.lbProgressStatus.string = `Load resources (${loaded >> 0}/${total})`;
                        onLoaded();
                    }
                }
            }
            else {
                this.barProgress.node.active = false;
                this._quickLogin();
            }
        }
    }

    // 登录大厅结果
    private _onLoginLobbyResult(e: lobby.events.LoginLobbyResult) {
        DEBUG && console.debug('# lobby.events.LoginLobbyResult', e);
        if (!e.bSucceed) {
            // 登陆失败，显示原因给用户
            DEBUG && console.error('# login err:', e.errorCode, e.errorDesc, e.errorDetail);
            games.ui.messageBox(e.errorDesc, (btn) => {
                if (btn == games.ui.MBBtn.Yes) {
                    this._quickLogin();
                } else {
                    game.end();
                }
            }, this);
            return;
        }
        // 登陆成功
        DEBUG && console.log('# login success, userId:', players.myself.userID);

        // 获取最新键值对
        lobby.updateKeyValueData(players.myself, yy.env.cfg.mainGameID, true);

        // 游戏需要断线重连（网赚版本不需要重连）
        if (e.needResumeRoom) {
            // 检测游戏更新
            let resumeInfo = lobby.service.getResumeGameInfo();
            let game = games.gameCenter.getGameByID(resumeInfo.gameID);
            if (game.hasNewVersion()) {
                let update = game.getRunningUpdate();
                if (!update) {
                    // 无更新开启游戏更新
                    update = game.updateToNewVersion();
                    if (!update) {
                        DEBUG && console.debug(`游戏${game.getGameID()}热更新失败`);
                        return;
                    }
                }
                DEBUG && console.debug(`游戏${game.getGameID()}监听热更新`);

                // 绑定监听更新事件  
                yy.event.on(this, games.events.UpdateEvent, (e) => {
                    if (!e || !e.autoUpdate)
                        return;
                    switch (e.eventCode) {
                        case games.events.UpdateEventCode.Failed:
                            DEBUG && console.debug(`游戏${game.getGameID()}热更新失败`);
                            if (e.autoUpdate.canRetry()) {
                                DEBUG && console.warn('提示重试下载操作');
                                e.autoUpdate.retry();
                            } else {
                                DEBUG && console.warn('不能重试');
                            }
                            break;
                        case games.events.UpdateEventCode.Progress:
                            DEBUG && console.debug(`游戏${game.getGameID()}热更新进度:${e.progress}`);
                            break;
                        case games.events.UpdateEventCode.Succeed:
                            DEBUG && console.debug(`游戏${game.getGameID()}热更新成功，恢复游戏场景`);
                            lobby.service.resumeGameWithUi();
                            break;
                    }
                });
                return;
            }
            // 恢复游戏场景
            this.barProgress.scrollTo(0.1, 1);
            lobby.service.resumeGameWithUi();
            return;
        }

        this.barProgress.node.active = true;
        this.barProgress.scrollTo(1, 0.9);
        this.scheduleOnce(this.chooseRoom.bind(this), 1);
    }

    // 快速登录  
    private _quickLogin() {
        if (!this.isTestLogin) {
            this.barProgress.value = 0;
            this.barProgress.node.active = true;
            this.lbProgressStatus.string = "Logining ...";
            this.barProgress.scrollTo(1, 0.6);

            if (lobby.service.getLoginState() === games.LoginState.Logined)
                lobby.service.reqLogoutLobby();
            // 不传参数，调用第三方token登录/注册
            lobby.service.reqLoginLobby();
        }
        else {
            // 调试登录模式，由专用UI执行登录流程，此处不处理登录事务
            this.lbProgressStatus.string = '';
            this.barProgress.value = 0;
        }
    }

    private block = false;
    private chooseRoom() {
        if (this.block)
            return;
        this.block = true;

        const game = YYExt.cfgGame;
        const gameInfo = YYExt.cfgGameInfo;
        if (!game || !gameInfo) {
            DEBUG && console.error('get game info failed:', YYExt.cfgGameID);
            return;
        }

        const noRoomTips = () => {
            const tips = MutiLang.getString("no_room_tip");
            this.lbProgressStatus.string = tips;
            this.barProgress.node.active = false;
            games.ui.messageBox(tips);
            this.block = false;
        }
        const gotoRoom = () => {
            this.barProgress.scrollTo(0.1, 1);
            games.gameRunHelper.gotoRoom(YYExt.cfgGame);
            this.block = false;
        }

        // 先检测是否有游戏房间
        if (gameInfo.isRoomsLoad) {
            if (gameInfo.rooms.length > 0) {
                gotoRoom();
            } else {
                noRoomTips();
            }
        }
        else {
            yy.event.on(this, lobby.events.GameRoomListUpdated, (e: lobby.events.GameRoomListUpdated) => {
                if (e.gameID != YYExt.cfgGameID) return;
                if (YYExt.cfgGameInfo.rooms.length > 0) {
                    gotoRoom();
                } else {
                    noRoomTips();
                }
            });
        }
    }

}
